package logic

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"time"

	monmodel "demo/cache"
	rabbitMQ "demo/internal/common/rabbitmq"
	"demo/internal/errorx"
	"demo/internal/svc"
	"demo/internal/types"
	"demo/model"

	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
)

type AnswerCreateLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
	modelA model.AnswerModel
	modelAD model.AnswerDetailModel
	modelS model.ServeyModel
	answerModel monmodel.AnswerModel
	answerStatModel monmodel.AnswerStatModel
}

const (
	ended = iota
	un_end
)
const (
	finished = iota
	un_finish
)

const (
	AnswerQueue = "answerQueue"
	DirectExchange = "directExchange"
	AnswerRoutingKey = "answerRoutingKey"
)

type WholeAnswer struct {
	Answer model.Answer `json:"answer"`
	AnswerDetails []*model.AnswerDetail `json:"answerDetails,optional,omitempty"`
}

func NewAnswerCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AnswerCreateLogic {
	return &AnswerCreateLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
		modelA: model.NewAnswerModel(svcCtx.Orm),
		modelAD: model.NewAnswerDetailModel(svcCtx.Orm),
		modelS: model.NewServeyModel(svcCtx.Orm,svcCtx.Config.Cache),
		answerModel: monmodel.NewAnswerModel(svcCtx.Config.Mongo.Url,svcCtx.Config.Mongo.Db,"answer",svcCtx.Config.Cache),
		answerStatModel: monmodel.NewAnswerStatModel(svcCtx.Config.Mongo.Url,svcCtx.Config.Mongo.Db,"answerStat",svcCtx.Config.Cache),
	}
}

func (l *AnswerCreateLogic) AnswerCreate(req *types.AnswerCreateRequest,remoteAddr string) (resp *types.StandredIdResponse, err error) {
	// todo: add your logic here and delete this line
	payload,ok := l.ctx.Value("payload").(string)
	if !ok{
		return nil,errorx.NewBizError(500,"用户ID获取失败")
	}
	userId,err := strconv.ParseInt(payload,10,64)
	if err != nil{
		return nil,errorx.NewBizError(500,"字符串格式转换错误")
	}

	var answer *model.Answer
	var answerDetails []*model.AnswerDetail
	// 校验servey是否已经结束并且是否存在
	l.modelS.Trans(l.ctx,func(context context.Context, session sqlx.Session) error {

		servey,err := l.modelS.FindOne(l.ctx,session,req.ServeyId)
		if err != nil {
			return err
		}
		if servey.IsDeleted == deleted || servey.IsEnd == ended {
			return errors.ErrUnsupported
		}
		answer = &model.Answer{
			CustomerId: userId,
			ServeyId: req.ServeyId,
			SubmitTime: time.Now().Unix(),
			IsFinished: finished,
			Duration: req.Duration,
			IpAddr: remoteAddr,
		}
		aId,err := l.modelA.InsertGetId(l.ctx,session,answer)
		if err != nil {
			return err
		}
		answerDetails = make([]*model.AnswerDetail,0)
		for _,answerDetail := range req.AnswerDetails {
			answerDetail := &model.AnswerDetail{
				AnswerId: aId,
				QuestionId: answerDetail.QuestionId,
				AnsContent: answerDetail.AnsContent,
			}
			answerDetails = append(answerDetails, answerDetail)
		}
		err = l.modelAD.BulkInsert(l.ctx,session,answerDetails)
		if err != nil {
			return err
		}
		answer.Id = aId

		// 保存于mongo中
		return nil
	})
	// go l.SaveDataInMon(answer,answerDetails)
	go l.UpdateAnswerStat(answer)
	// 保存消息至mq中
	optMq := rabbitMQ.NewOptMq(l.svcCtx.Config.Rabbit.Url)
	wholeAnswer := &WholeAnswer{
		Answer: *answer,
		AnswerDetails: answerDetails,
	}
	byteWholeAnswer,err := json.Marshal(wholeAnswer)
	if err != nil {
		return nil,errorx.NewBizError(500,err.Error())
	}
	err = optMq.PublishDirect(AnswerQueue,DirectExchange,AnswerRoutingKey,byteWholeAnswer,true)
	if err != nil {
		return nil,errorx.NewBizError(500,err.Error())
	}
	return &types.StandredIdResponse{
		Code: 200,
		Msg: "create success",
		Data: types.IdRequest{
			Id: answer.Id,
		},
	},nil
}

func (l *AnswerCreateLogic)SaveDataInMon(data string)(bool,error){

	ctx,cancel := context.WithTimeout(context.Background(),5*time.Second)
	defer cancel()
	var wholeAnswer *WholeAnswer
	byteWS := []byte(data)
	json.Unmarshal(byteWS,&wholeAnswer)
	answer := wholeAnswer.Answer
	answerDetails := wholeAnswer.AnswerDetails
	monAnswer := &monmodel.Answer{
		Id: answer.Id,
		ServeyId: answer.ServeyId,
		CustomerId: answer.CustomerId,
		SubmitTime: answer.SubmitTime,
		Duration: answer.Duration,
		IsFinished: answer.IsFinished,
	}
	monAnswerDetails := make([]*monmodel.AnswerDetailItem,0)
	for _,val := range answerDetails {
		monAnswerDetail := &monmodel.AnswerDetailItem{
			AnswerId: val.AnswerId,
			QuestionId: val.QuestionId,
			AnsContent: val.AnsContent,
		}
		monAnswerDetails = append(monAnswerDetails, monAnswerDetail)
	}
	monAnswer.AnswerDetails = monAnswerDetails
	l.answerModel.Insert(ctx,monAnswer)
	return true,nil
}

func (l *AnswerCreateLogic)UpdateAnswerStat(answer *model.Answer){
	var ansStat *monmodel.AnswerStat
	now := time.Now()
	ctx,cancel := context.WithTimeout(context.Background(),5*time.Second)
	defer cancel()
	midnight := time.Date(now.Year(),now.Month(),now.Day(),0,0,0,0,now.Location())
	tsp := midnight.Unix()
	id := strconv.FormatInt(tsp,10) + strconv.FormatInt(answer.CustomerId,10)
	monAsw,err := l.answerStatModel.FindOne(ctx,id)
	if monAsw == nil{
		ansStat = &monmodel.AnswerStat{
			Id: id,
			AnswerNum: 1,
			AverageDuration: float64(answer.Duration),
		}
		err = l.answerStatModel.Insert(ctx,ansStat)
		fmt.Println("err is :",err)
	}else{
		ansStat = &monmodel.AnswerStat{
			Id: id,
			AnswerNum: monAsw.AnswerNum + 1,
			AverageDuration: (monAsw.AverageDuration * float64(monAsw.AnswerNum) + float64(answer.Duration))/float64(monAsw.AnswerNum + 1),
		}
		l.answerStatModel.Update(ctx,ansStat)
	}

}
